﻿using System;
using System.Diagnostics;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Windows.Forms;
using HPSocketCS;
using TcpServer.DataProcessor;
using Hjt212Parser;
using TcpServer.Facade;
using TcpServer.Orm;
using log4net;

namespace TcpServer
{

    public partial class FrmServer : Form
    {
        private static readonly ILog log = LogManager.GetLogger(typeof(FrmServer));

        private delegate void ShowMsg(string msg);
        private ShowMsg _showMsgDelegate;
        public FrmServer()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            try
            {
                //var a= BaseInfoBufferAndHelper.GetAlarmThrsholdTimeType(DateTime.Now);
                //var a = BaseInfoBufferAndHelper.GetAlarmThrsholdTimeType("白天(6:00 - 22:00)");

                // 加个委托显示msg,因为on系列都是在工作线程中调用的,ui不允许直接操作
                _showMsgDelegate = AddMsg;

                // 设置服务器事件
                BufferFacade.Server.OnPrepareListen += OnPrepareListen;
                BufferFacade.Server.OnAccept += OnAccept;
                BufferFacade.Server.OnSend += OnSend;
                BufferFacade.Server.OnReceive += OnReceive;
                BufferFacade.Server.OnClose += OnClose;
                BufferFacade.Server.OnShutdown += OnShutdown;

                // 启动线程
                ThreadPool.QueueUserWorkItem(Info);
                ThreadPool.QueueUserWorkItem(Persist);
                //ThreadPool.QueueUserWorkItem(Persist);
                ThreadPool.QueueUserWorkItem(Biz);
                ThreadPool.QueueUserWorkItem(Biz);
                //ThreadPool.QueueUserWorkItem(Biz);
                ThreadPool.QueueUserWorkItem(IssueLimitValue);
            }
            catch (Exception ex)
            {
                AddMsg(ex.Message);
            }
        }

        private void btnStart_Click(object sender, EventArgs e)
        {
            try
            {
                string ip = txtIpAddress.Text.Trim();
                ushort port = ushort.Parse(txtPort.Text.Trim());

                BufferFacade.Server.IpAddress = ip;
                BufferFacade.Server.Port = port;
                // 启动服务
                if (BufferFacade.Server.Start())
                {
                    Text = $" ({ip}:{port})";
                    AddMsg($"Server Start OK -> ({ip}:{port})");
                    btnStart.Enabled = false;
                }
                else
                {
                    throw new Exception(
                        $"Server Start Error -> {BufferFacade.Server.ErrorMessage}({BufferFacade.Server.ErrorCode})");
                }
            }
            catch (Exception ex)
            {
                AddMsg(ex.Message);
            }
        }
        HandleResult OnPrepareListen(IntPtr soListen)
        {
            // 监听事件到达了,一般没什么用吧?
            return HandleResult.Ok;
        }

        HandleResult OnAccept(IntPtr connId, IntPtr pClient)
        {
            // 客户进入了
            // 获取客户端ip和端口
            string ip = string.Empty;
            ushort port = 0;
            if (BufferFacade.Server.GetRemoteAddress(connId, ref ip, ref port))
            {
                AddMsg($" > [{connId},OnAccept] -> Client({ip}:{port})");
            }
            else
            {
                AddMsg($" > [{connId},OnAccept] -> Server_GetClientAddress() Error");
            }
            return HandleResult.Ok;
        }

        HandleResult OnSend(IntPtr connId, IntPtr pData, int length)
        {
            // 服务器发数据了
            //AddMsg(string.Format(" > [{0},OnSend] -> ({1} bytes)", connId, length));
            return HandleResult.Ok;
        }

        HandleResult OnReceive(IntPtr connId, IntPtr pData, int length)
        {
            // 数据到达了
            try
            {
                // 获取客户端ip和端口
                string ip = string.Empty;
                ushort port = 0;
                if (BufferFacade.Server.GetRemoteAddress(connId, ref ip, ref port))
                {
                    string message = Marshal.PtrToStringAnsi(pData, length);
                    AddMsg(message);
                    if (!String.IsNullOrWhiteSpace(message))
                    {
                        string mn = Parser.GetStringByKey("MN", message);
                        if (!String.IsNullOrWhiteSpace(mn))
                        {
                            string[] msgs = message.Split('\n');
                            foreach (var msg in msgs)
                            {
                                if (!string.IsNullOrWhiteSpace(msg) && Parser.IsHjt212Protocol(msg))
                                {
                                    var flag = Parser.GetStringByKey("Flag", msg);
                                    var qn = Parser.GetStringByKey("QN", msg);
                                    var cn = Parser.GetStringByKey("CN", msg);
                                    var valid = Parser.IsLengthRight(msg);
                                    if (valid && qn != null && flag != null && flag.Equals("1"))
                                    {
                                        var response = "ST=91;CN=9014;CP=&&QN=" + qn + ";CN=" + cn + "&&";
                                        var result = "##" + $"{response.Length:d4}" + response +
                                                     $"{Crc.WrapByCrc(response,"monitor"):x4}" + "\r\n";
                                        byte[] sendBytes = Encoding.Default.GetBytes(result);
                                        BufferFacade.Server.Send(connId, sendBytes, sendBytes.Length);
                                    }
                                    BufferFacade.EnqueueToMessageQueue(QueueType.Both, new SocketClientInfo { ConnId = connId, IpAddress = ip, Port = port, ReceivedMsg = msg, LogonTime = DateTime.Now, MN = mn });
                                }
                            }
                            BufferFacade.AddSocket(connId, mn);
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                log.Error(ex);
            }
            return HandleResult.Ok;
        }

        private HandleResult Disconnect(IntPtr connId)
        {
            string mn = BufferFacade.RemoveSocket(connId);
            log.Info("Disconnect:"+ mn);
            AddMsg(connId + " disconnected,MN:" + mn);
            return HandleResult.Ok;
        }
        HandleResult OnClose(IntPtr connId, SocketOperation enOperation, int errorCode)
        {
            return Disconnect(connId);
        }

        HandleResult OnShutdown()
        {
            // 服务关闭了
            log.Error( "系统关掉了!");
            return HandleResult.Ok;
        }
        /// <summary>
        /// 往listbox加一条项目
        /// </summary>
        /// <param name="msg"></param>
        void AddMsg(string msg)
        {
            if (lbxMsg.InvokeRequired)
            {
                // 很帅的调自己
                lbxMsg.Invoke(_showMsgDelegate, msg);
            }
            else
            {
                if (lbxMsg.Items.Count > 100)
                {
                    lbxMsg.Items.RemoveAt(0);
                }
                lbxMsg.Items.Add(msg);
                lbxMsg.TopIndex = lbxMsg.Items.Count - (int)(lbxMsg.Height / lbxMsg.ItemHeight);
            }
        }



        private void frmServer_FormClosed(object sender, FormClosedEventArgs e)
        {
            BufferFacade.Server.Destroy();
        }

        public void Persist(object state)
        {
            while (true)
            {
                try
                {
                    IProcessor persistenceProcessor = new PersistenceProcessor();
                    using (DataCommunicationEntities context = new DataCommunicationEntities())
                    {
                        while (true)
                        {
                            SocketClientInfo info = BufferFacade.DequeueFromMessageQueue(QueueType.Persistence);
                            if (info != null)
                            {
                                log.Debug( Thread.CurrentThread.GetHashCode() + "-Persist"+ "开始持久化:" + info.ReceivedMsg);
                                persistenceProcessor.Persist(context, info);
                                context.SaveChanges();
                            }
                            Thread.Sleep(1);
                        }
                    }
                }
                catch (Exception ex)
                {
                    log.Error( ex);
                }
            }
            // ReSharper disable once FunctionNeverReturns
        }
        public void Biz(object state)
        {
            while (true)
            {
                try
                {
                    IProcessor biz2011Processor = new Platform2011Processor();
                    IProcessor biz2021Processor = new Platform2021Processor();
                    IProcessor biz2031Processor = new Platform2031Processor();
                    IProcessor biz2031ToMonthProcessor = new Platform2031ToMonthProcessor();
                    IProcessor biz2031ToYearProcessor = new Platform2031ToYearProcessor();
                    IProcessor bizLatitudeLongitude2031Processor = new LatitudeLongitude2031Processor();
                    IProcessor biz2051Processor = new Platform2051Processor();
                    IProcessor biz2061Processor = new Platform2061Processor();
                    IProcessor alarm2011Processor = new Alarm2011Processor();
                    IProcessor alarmAvgProcessor = new AlarmAvgProcessor();
                    IProcessor biz9011Processor = new Platform9011Processor();
                    IProcessor biz9012Processor = new Platform9012Processor();
                    IProcessor biz3081Processor = new Platform3081Processor();
                    using (DustEntities context = new DustEntities())
                    {
                        while (true)
                        {
                            SocketClientInfo info = BufferFacade.DequeueFromMessageQueue(QueueType.BizProcess);
                            if (info != null)
                            {
                                var cn = Parser.GetStringByKey("CN", info.ReceivedMsg);
                                log.Debug( Thread.CurrentThread.GetHashCode() + "-Biz"+"开始处理" + cn + ":" + info.ReceivedMsg);
                                switch (cn)
                                {
                                    case "2011":
                                        biz2011Processor.Persist(context, info);
                                        alarm2011Processor.Persist(context, info);
                                        break;
                                    case "2021":
                                        biz2021Processor.Persist(context, info);
                                        alarmAvgProcessor.Persist(context, info);
                                        break;
                                    case "2031":
                                        biz2031Processor.Persist(context, info);
                                        biz2031ToMonthProcessor.Persist(context, info);
                                        biz2031ToYearProcessor.Persist(context, info);
                                        alarmAvgProcessor.Persist(context, info);
                                        bizLatitudeLongitude2031Processor.Persist(context, info);
                                        break;
                                    case "2051":
                                        biz2051Processor.Persist(context, info);
                                        alarmAvgProcessor.Persist(context, info);
                                        break;
                                    case "2061":
                                        biz2061Processor.Persist(context, info);
                                        alarmAvgProcessor.Persist(context, info);
                                        break;
                                    case "9011":
                                        biz9011Processor.Persist(context, info);
                                        break;
                                    case "9012":
                                        biz9012Processor.Persist(context, info);
                                        break;
                                    case "3081":
                                        biz3081Processor.Persist(context, info);
                                        break;
                                }
                            }
                            Thread.Sleep(1);
                        }
                    }
                }
                catch (Exception ex)
                {
                    log.Error( ex);
                }
            }
            // ReSharper disable once FunctionNeverReturns
        }
        public void Info(object state)
        {
            while (true)
            {
                try
                {
                    log.Info( BufferFacade.GetMNs().Count + "/" + BufferFacade.Server.ConnectionCount);
                    log.Info( "等待持久和处理的记录数分别为:" + BufferFacade.MessageQueue4Persistence.Count + "和" + BufferFacade.MessageQueue4BizProcess.Count);
                    Thread.Sleep(5 * 60 * 1000);
                }
                catch (Exception ex)
                {
                    log.Error(ex);
                }
            }
            // ReSharper disable once FunctionNeverReturns
        }

        public void IssueLimitValue(object state)
        {
            while (true)
            {
                try
                {
                    var sockets = BufferFacade.GetAllSockets();
                    foreach (var item in sockets)
                    {
                        if (!string.IsNullOrWhiteSpace(item.Value))
                        {
                            using (var ctx = new DustEntities())
                            {
                                var issueItems = ctx.V_Threshold.Where(t => t.DevCode != null && t.DevCode.Contains(item.Value)).Where(t => !t.执行结果.Contains("不同步")).Where(t => !t.执行结果.Contains("成功")).ToList();
                                foreach (var issue in issueItems)
                                {
                                    var setion = BaseInfoBufferAndHelper.GetAlarmThrsholdTimeType(issue.时间类型名称);
                                    var qn = DateTime.Now.ToString("yyyyMMddHHmmssfff");
                                    var result = "QN=" + qn
                                                 + ";ST=20;CN=3088;PW=123456" + ";MN=" + item.Value
                                                 + ";Flag=1;CP=&&" + issue.因子代码 + "-Thd=" + issue.报警阈值.ToString("f2")
                                        + "," + issue.因子代码 + "-DateType=" + issue.报警限值时间类型ID + ","
                                        + issue.因子代码 + "-BeginTime=" + setion.BeginHour.ToString("D2") + setion.BeginMinute.ToString("D2") + ","
                                        + issue.因子代码 + "-EndTime=" + setion.EndHour.ToString("D2") + setion.EndMinute.ToString("D2") + ","
                                        + issue.因子代码 + "-SiteType=" + issue.SiteTypeID + "&&";
                                    result = "##" + result.Length.ToString("D4") + result + Crc.WrapByCrc(result,"monitor") + "\r\n";
                                    AddMsg("Issue:" + result);
                                    if (item.Key != IntPtr.Zero)
                                    {
                                        var thd = ctx.SetFactorThresholds.FirstOrDefault(t => t.ID == issue.ID);
                                        if (thd != null)
                                        {
                                            thd.QN = qn;
                                            ctx.SaveChanges();
                                        }
                                        byte[] sendBytes = Encoding.Default.GetBytes(result);
                                        BufferFacade.Server.Send(item.Key, sendBytes, sendBytes.Length);
                                        log.Info("IssueThreshold"+result);
                                        Thread.Sleep(5000);
                                    }
                                }
                            }
                        }
                    }
                }
                catch (Exception ex)
                {
                    log.Error(ex);
                }
                finally
                {
                    try
                    {
                        Thread.Sleep(10000);
                    }
                    catch (Exception)
                    {
                        // ignored
                    }
                }
            }
        }

        private void FrmServer_FormClosing(object sender, FormClosingEventArgs e)
        {
            try
            {
                Process.GetCurrentProcess().Kill();
            }
            catch (Exception)
            {
                // ignored
            }
        }
    }
}
